/*
 * util.cpp
 *
 * Copyright (C) 1999, Ben Swartzlander
 * This file is part of Q2BotCore.
 * For conditions of distribution and use,
 * see the accompanying README file.
 */

#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <limits.h>
#include "util.h"

PRINTFUNC printFunc;
PRINTFUNC printFunc2;
int randseed=362436069;

void setPrintFuncs(PRINTFUNC p, PRINTFUNC p2) {
	printFunc=p;
	printFunc2=p2;
}

void print(char *format, ...) {
	va_list args;
	char buffer[8192];
	int i,j;

	if(printFunc==0) return;

	va_start(args, format);
	vsprintf(buffer, format, args);
	va_end(args);
	buffer[8191]='\0';
	printFunc(buffer);
}

void printe(char *format, ...) {
	va_list args;
	char buffer[8192];
	int i,j;

	if(printFunc2==0) return;

	va_start(args, format);
	vsprintf(buffer, format, args);
	va_end(args);
	buffer[8191]='\0';
	printFunc2(buffer);
}


float yawFromVect(vec3_t delta) {
	if(delta[0]==0) {
		if(delta[1]>=0) {
			return PI/2;
		} else {
			return 3*PI/2;
		}
	} else {
		if(delta[0]>=0) {
			if(delta[1]>=0) {
				return (float)atan(delta[1]/delta[0]);
			} else {
				return 2*PI+(float)atan(delta[1]/delta[0]);
			}
		} else {
			return PI+(float)atan(delta[1]/delta[0]);
		}
	}
}

float pitchFromVect(vec3_t delta) {
	float delta2;

	delta2=sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
	if(delta2==0) {
		if(delta[2]>=0) {
			return PI/2;
		} else {
			return 3*PI/2;
		}
	} else {
		if(delta2>=0) {
			if(delta[2]>=0) {
				return (float)atan(delta[2]/delta2);
			} else {
				return 2*PI+(float)atan(delta[2]/delta2);
			}
		} else {
			return PI+(float)atan(delta[2]/delta2);
		}
	}
}

float distFromVect(vec3_t u,vec3_t v) {
	float x,y,z;

	x=v[0]-u[0];
	y=v[1]-u[1];
	z=v[2]-u[2];
	return (float)sqrt(x*x+y*y+z*z);
}

#define USE_X86_ASM
#ifdef USE_X86_ASM

double clockFrequency(void) {
	__int64	i64_perf_start, i64_perf_freq, i64_perf_end;
	__int64	i64_clock_start,i64_clock_end;
	double d_loop_period, d_clock_freq;

	QueryPerformanceFrequency((LARGE_INTEGER*)&i64_perf_freq);

	QueryPerformanceCounter((LARGE_INTEGER*)&i64_perf_start);
	i64_perf_end = 0;

	RDTSC(i64_clock_start);
	while(i64_perf_end<i64_perf_start+2500000)
	{
		QueryPerformanceCounter((LARGE_INTEGER*)&i64_perf_end);
	}
	RDTSC(i64_clock_end);

	i64_clock_end -= i64_clock_start;

	d_loop_period = ((double)(i64_perf_freq)) / 2500000.0;
	d_clock_freq = ((double)(i64_clock_end & 0xffffffff))*d_loop_period;

	return d_clock_freq;
}

void randomize(void) {
	_asm {
		_emit 0x0F
		_emit 0x31
		mov DWORD PTR randseed,eax
	}
}

unsigned short int irand(void) {
	unsigned short i;

	_asm {
		mov		edx,69069
		mov		eax,randseed
		mul		edx
		add		eax,1
		mov		randseed,eax
		shr		eax,16
		mov		i,ax
	}
	return i;
}

unsigned long int lrand(void) {
	unsigned long int i;

	_asm {
		mov		edx,69069
		mov		eax,randseed
		mul		edx
		add		eax,1
		mov		ebx,eax
		shr		ebx,16
		mov		edx,69069
		mul		edx
		add		eax,1
		mov		randseed,eax
		and		eax,0xffff0000
		or		eax,ebx
		mov		i,eax
	}
	return i;
}
#else
// C replacements go here.
double clockFrequency(void) {
	__int64	i64_perf_start, i64_perf_freq, i64_perf_end;
	__int64	i64_clock_start,i64_clock_end;
	double d_loop_period, d_clock_freq;

	QueryPerformanceFrequency((LARGE_INTEGER*)&i64_perf_freq);

	QueryPerformanceCounter((LARGE_INTEGER*)&i64_perf_start);
	i64_perf_end = 0;

	RDTSC(i64_clock_start);
	while(i64_perf_end<i64_perf_start+2500000)
	{
		QueryPerformanceCounter((LARGE_INTEGER*)&i64_perf_end);
	}
	RDTSC(i64_clock_end);

	i64_clock_end -= i64_clock_start;

	d_loop_period = ((double)(i64_perf_freq)) / 2500000.0;
	d_clock_freq = ((double)(i64_clock_end & 0xffffffff))*d_loop_period;

	return d_clock_freq;
}

void randomize(void)
{
	srand(time(NULL));
}

unsigned short int irand(void)
{
	// ouchhack
	return (unsigned short int)rand();
}

unsigned long int lrand(void)
{
#if(UINT_MAX == ULONG_MAX)
	return rand();
#else

	// for 64 bit linux
	long i1,i2;

	i1 = rand();
	i2 = rand();
	
	// left shift 32 bits to cover 0s
	i1 << 32;

	// return them OR'd together.
	return (i1 | i2);
#endif
}
#endif